package Utils;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import Exceptions.DataAccessException;


/**
 * this is a help class for simplifying work with xml
 * it includes several useful and methods for common actions with xml 
 */
public class XmlParseHelper {

	/**
	 * finds all child xml elements by specific name. useful help method for parsing xml files
	 * @param father - the element to find his children
	 * @param childrenName - name for search
	 * @return - ArrayList<Element> with found elements (empty if no elements found or bad params given)
	 */
	public static ArrayList<Element> getChildrenByName(Element father, String childrenName){
		ArrayList<Element> resultList = new ArrayList<Element>();
		if(father == null || childrenName == null){
			return resultList;
		}
		NodeList childNodes = father.getElementsByTagName(childrenName);
		for (int i = 0; i < childNodes.getLength(); i++){
			if(childNodes.item(i).getParentNode()==father){
				resultList.add((Element) childNodes.item(i));
			}
		}
	
		return resultList;
	}

	/**
	 * finds first child xml element by specific name. useful help method for parsing xml files
	 * @param father - the element to find his children
	 * @param childrenName - name for search
	 * @return - found element
	 */
	public static Element getFirstChildByName(Element father, String childrenName){
		if (getChildrenByName(father, childrenName).size()>0){
			return getChildrenByName(father, childrenName).get(0);
		}
		else{
			return null;
		}
	}

	/**
	 * help function for shorting xml creating functions.
	 * creates new element by given name, appends it to parent element and adds necessary content to the son
	 * @param document - the document for element creation
	 * @param resultElement - parent element
	 * @param sonName - name of new element
	 * @param sonContent - content of new element
	 * @return new created element
	 */
	public static Element appendNewElementToParent(Document document, Element resultElement, String sonName, String sonContent){
		Element sonElement = document.createElement(sonName);
		sonElement.setTextContent(sonContent);
		resultElement.appendChild(sonElement);
	
		return sonElement;
	}

	/**
	 * help function for shorting xml creating functions.
	 * creates new element by given name and appends it to parent element (the content of new element is empty)
	 * @param document - the document for element creation
	 * @param resultElement - parent element
	 * @param sonName - name of new element
	 * @return new created element
	 */
	public static Element appendNewElementToParent(Document document, Element resultElement, String sonName){
		Element sonElement = document.createElement(sonName);
		resultElement.appendChild(sonElement);
	
		return sonElement;
	}

	/**
	 * help method - creates a new empty dom xml doc
	 * @return new doc
	 */
	public static Document createNewDocument(){
		DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = null;
		try {
			docBuilder = docFactory.newDocumentBuilder();
		}
		catch (ParserConfigurationException e) {
			//assumption: we never should get here
			e.printStackTrace();
		}
		Document document = docBuilder.newDocument();
		return document;
	}

	/**
	 * extract xml document from file by file's name
	 * @param filename - the xml file name
	 * @return document
	 * @throws DataAccessException 
	 */
	public static Document getDocumentFromFile(String filename) throws DataAccessException{
	
		Document result = null;
	
		File file = new File(filename);
		if(!file.exists()){
			throw new DataAccessException();
		}
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		try{
			DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
			result = documentBuilder.parse(file);
		}
		catch (Exception e){
			//Should not get here
		}
	
		return result;
	}

	/**
	 * help function - converts string of date and time (cinema xml format) to java date object 
	 * @param dateString - string to convert
	 * @return date
	 */
	public static Date convertCinemaDateStringToDateObject(String dateString){
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
		Date date = null;
		try {
			date = df.parse(dateString);
		}
		catch (Exception e) {
			//assumption: we never get here
			e.printStackTrace();
		}
		return date;
	}

	/**
	 * converts NodeList object to ArrayList<Element>
	 * @param list - list to convert
	 * @return  ArrayList<Element>  - converted list
	 */
	public static ArrayList<Element> convertNodeListToElementArrayList(NodeList list){
		ArrayList<Element> resultList = new ArrayList<Element>();
		for (int i=0; i<list.getLength(); i++){
			resultList.add((Element) list.item(i));
		}
		
		return resultList;
	}

	/**
	 * help method - writes xml doc to file
	 * @param fileName - target file
	 * @param document - doc to write
	 */
	public static void saveXmlFile(String fileName, Document document){
		File file = new File(fileName);
	
		// write the content into xml file
		TransformerFactory transformerFactory = TransformerFactory.newInstance();
		Transformer transformer;
		try {
			transformer = transformerFactory.newTransformer();
			DOMSource source = new DOMSource(document);
			StreamResult result = new StreamResult(file);
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.transform(source, result);
		}
		catch (TransformerConfigurationException e) {
			//assumption: we never should get here
			e.printStackTrace();
		}
		catch (TransformerException e) {
			//assumption: we never should get here
			e.printStackTrace();
		}
	}
	
}
